home *** CD-ROM | disk | FTP | other *** search
/ Assassins - Ultimate CD Games Collection 2 / Assassins 2 - Ultimate Games No. 2 (1995)(Weird Science)[!][Amiga-CD32-CDTV].iso / disks / mv-9.dms / mv-9.adf / GiffToIff / giftrans / Giftrans.Src / source / giftrans.c < prev    next >
C/C++ Source or Header  |  1995-04-11  |  24KB  |  880 lines

  1. /*
  2. ** GIFtrans v1.11.1
  3. **
  4. ** Convert any GIF file into a GIF89a
  5. ** Allows for setting the transparent or background color, changing colors,
  6. ** adding or removing comments. Also code to analyze GIF contents.
  7. **
  8. ** Copyright (c) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de>
  9. **
  10. ** Permission to use, copy, modify, and distribute this software for any
  11. ** purpose and without fee is hereby granted, provided that the above
  12. ** copyright notice appears in all copies. This software is provided "as is"
  13. ** and without any express or implied warranties.
  14. **
  15. ** This program has been tested on a HP9000/720 with HP-UX A.08.07
  16. ** In this environment, neither lint -u nor gcc -Wall produce any messages.
  17. ** If you encounter any errors or need to make any changes to port it
  18. ** to another platform, please contact me.
  19. **
  20. ** Known bugs:
  21. **    -B flag won't work if there's an Extension between the Global Color
  22. **    Table and the Image Descriptor (or Graphic Control Extension). If -V
  23. **    has been specified, a Warning Message will be displayed.
  24. **    Will be fixed in 2.0
  25. **    Always outputs GIF89a. Shouldn't do this if version is newer.
  26. **    -D option may output changed data instead of original data, use
  27. **    with caution, best only with then -L option.
  28. **
  29. ** Version history
  30. **
  31. ** Version 1.11.1 - 11.8.94
  32. **    Allows for use of the -g option without the -B option.
  33. **
  34. ** Version 1.11 - 21.7.94
  35. **    Moved Plain Text Extension to the Extensions section where it belongs.
  36. **    Accept Unknown Extension Labels.
  37. **    Incorporated MS-DOS port by enzo@hk.net (Enzo Michelangeli).
  38. **    Added -o and -e options to redirect stdout and stderr.
  39. **    Added -D debug flag.
  40. **
  41. ** Version 1.10.2 - 22.6.94
  42. **    Support for -DRGBTXT flag.
  43. **
  44. ** Version 1.10.1 - 21.6.94
  45. **    Different rgb.txt file FreeBSD/386BSD.
  46. **
  47. ** Version 1.10 - 19.6.94
  48. **    Added -g option to change a color in the global color table.
  49. **    Added -B option to change the color for the transparent color index.
  50. **
  51. ** Version 1.9.1 - 7.6.94
  52. **    Different rgb.txt files for X11 and Open Windows.
  53. **
  54. ** Version 1.9 - 1.6.94
  55. **    Fixed a bug which caused color names to be rejected.
  56. **
  57. ** Version 1.8 - 30.5.94
  58. **    Accept #rrggbb style arguments.
  59. **    Do nothing if rgb-color not found in GIF.
  60. **
  61. ** Version 1.7 - 16.5.94
  62. **    Added -l option to only list the color table.
  63. **    Added -L option for verbose output without creating a gif.
  64. **    Added -b option to change the background color index.
  65. **    Display all matching color names for color table entries.
  66. **    Fixed a bug which caused bad color names if rgb.txt starts with
  67. **        whitespace.
  68. **    Doesn't use strdup anymore.
  69. **    Fixed =& bug on dec machines.
  70. **
  71. ** Version 1.6 - 5.4.94
  72. **    Added color names recognition.
  73. **
  74. ** Version 1.5 - 15.3.94
  75. **    Added basic verbose output to analyze GIFs.
  76. **
  77. ** Version 1.4 - 8.3.94
  78. **    Fixed off-by-one bug in Local Color table code.
  79. **    Added -c and -C options to add or remove a comment.
  80. **    Transparency is no longer the default.
  81. **
  82. ** Thanx for bug reports, ideas and fixes to
  83. **    patricka@cs.kun.nl (Patrick Atoon)
  84. **    wes@msc.edu (Wes Barris)
  85. **    pmfitzge@ingr.com (Patrick M. Fitzgerald)
  86. **    hoesel@chem.rug.nl (Frans van Hoesel)
  87. **    boardman@jerry.sal.wisc.edu (Dan Boardman)
  88. **    krweiss@chip.ucdavis.edu (Ken Weiss)
  89. **    chuck.musciano@harris.com (Chuck Musciano)
  90. **    heycke@camis.stanford.edu (Torsten Heycke)
  91. **    claw@spacsun.rice.edu (Colin Law)
  92. **    jwalker@eos.ncsu.edu (Joseph C. Walker)
  93. **    Bjorn.Borud@alkymi.unit.no (Bjorn Borud)
  94. **    Christopher.Vance@adfa.oz.au (CJS Vance)
  95. **    pederl@norway.hp.com (Peder Langlo)
  96. **    I.Rutson@bradford.ac.uk (Ian Rutson)
  97. **    Nicolas.Pioch@enst.fr (Nicolas Pioch)
  98. **    john@charles.CS.UNLV.EDU (John Kilburg)
  99. **    enzo@hk.net (Enzo Michelangeli)
  100. **    twv@hpwtwe0.cup.hp.com (Terry von Gease)
  101. **
  102. ** Original distribution site is
  103. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.c
  104. ** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at
  105. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.1
  106. ** To compile for MS-DOS, you need getopt:
  107. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/getopt.c
  108. ** MS-DOS executable can be found at
  109. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.exe
  110. ** A template rgb.txt for use with the MS-DOS version can be found at
  111. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/rgb.txt
  112. ** Additional info can be found on
  113. **    http://melmac.corp.harris.com/transparent_images.html
  114. */
  115.  
  116. #undef   X11        /* When using X Window System */
  117. #undef    OPENWIN        /* When using Open Windows */
  118. #undef    X386        /* When using FreeBSD/386BSD */
  119. #undef    MSDOS        /* When using Borland C (maybe MSC too) */
  120. #define  AMIGA    /* When using Amiga SAS/C 6.55+ */
  121.  
  122. char header[]="GIFtrans v1.11.1\n(c) 1994 by Andreas Ley\n";
  123.  
  124. #ifndef RGBTXT
  125. #ifdef X11
  126. #define    RGBTXT    "/usr/lib/X11/rgb.txt"
  127. #else /* X11 */
  128. #ifdef OPENWIN
  129. #define    RGBTXT    "/usr/openwin/lib/rgb.txt"
  130. #else /* OPENWIN */
  131. #ifdef X386
  132. #define    RGBTXT    "/usr/X386/lib/X11/rgb.txt"
  133. #else /* X386 */
  134. #ifdef MSDOS
  135. #define    RGBTXT    "rgb.txt"
  136. #else /* MSDOS */
  137. #ifdef AMIGA
  138. #define  RGBTXT   "usr:lib/X11/rgb.txt"
  139. #else /* AMIGA */
  140. #define RGBTXT    "";
  141. #endif /* AMIGA */
  142. #endif /* MSDOS */
  143. #endif /* X386 */
  144. #endif /* OPENWIN */
  145. #endif /* X11 */
  146. #endif /* RGBTXT */
  147.  
  148. #include <stdlib.h>
  149. #include <stdio.h>
  150. #include <string.h>
  151. #include <errno.h>
  152. #ifndef MSDOS
  153. #include <unistd.h>
  154. #ifndef AMIGA
  155. #include <sys/param.h>
  156. #endif
  157. #else
  158. #include <fcntl.h>
  159. #include "getopt.c"
  160. #endif
  161.  
  162. #ifndef MAXPATHLEN
  163. #define MAXPATHLEN 256
  164. #endif /* MAXPATHLEN */
  165.  
  166. #ifndef AMIGA
  167. #define    FALSE    (0)         /* This is the naked Truth */
  168. #define    TRUE    (1)         /* and this is the Light */
  169. #endif
  170.  
  171. #define    SUCCESS    (0)
  172. #define    FAILURE    (1)
  173.  
  174. struct entry {
  175.     struct entry    *next;
  176.     char        *name;
  177.     int        red;
  178.     int        green;
  179.     int        blue;
  180.     } *root;
  181.  
  182. #define    NONE    (-1)
  183. #define    OTHER    (-2)
  184. #define    RGB    (-3)
  185.  
  186. struct color {
  187.     int        index;
  188.     int        red;
  189.     int        green;
  190.     int        blue;
  191.     } bc,tc,tn,go,gn;
  192.  
  193. static char    *image,*comment;
  194. static int    skipcomment,list,verbose,output,debug;
  195. static long int    pos;
  196.  
  197. static char    rgb[] = RGBTXT;
  198. static char    true[] = "True";
  199. static char    false[] = "False";
  200.  
  201. #define    readword(buffer)    ((buffer)[0]+256*(buffer)[1])
  202. #define    readflag(buffer)    ((buffer)?true:false)
  203. #define    hex(c)            ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0')
  204.  
  205.  
  206. void dump(adr,data,len)
  207. long int    adr;
  208. unsigned char    *data;
  209. size_t        len;
  210. {
  211.     int    i;
  212.  
  213.     while (len>0) {
  214.         (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),"");
  215.         for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--)
  216.             (void)fprintf(stderr,"%s%02x",i==8?"  ":" ",*data);
  217.         (void)fprintf(stderr,"\n");
  218.     }
  219. }
  220.  
  221.  
  222.  
  223. void writedata(dest,data,len)
  224. FILE        *dest;
  225. unsigned char    *data;
  226. size_t        len;
  227. {
  228.     unsigned char    size;
  229.  
  230.     while (len) {
  231.         size=len<256?len:255;
  232.         (void)fwrite((void *)&size,1,1,dest);
  233.         (void)fwrite((void *)data,(size_t)size,1,dest);
  234.         data+=size;
  235.         len-=size;
  236.     }
  237.     size=0;
  238.     (void)fwrite((void *)&size,1,1,dest);
  239. }
  240.  
  241.  
  242. void skipdata(src)
  243. FILE    *src;
  244. {
  245.     unsigned char    size,buffer[256];
  246.  
  247.     do {
  248.         pos=ftell(src);
  249.         (void)fread((void *)&size,1,1,src);
  250.         if (debug)
  251.             dump(pos,&size,1);
  252.         if (debug) {
  253.             pos=ftell(src);
  254.             (void)fread((void *)buffer,(size_t)size,1,src);
  255.             dump(pos,buffer,(size_t)size);
  256.         }
  257.         else
  258.             (void)fseek(src,(long int)size,SEEK_CUR);
  259.     } while (!feof(src)&&size>0);
  260. }
  261.  
  262.  
  263. void transblock(src,dest)
  264. FILE    *src;
  265. FILE    *dest;
  266. {
  267.     unsigned char    size,buffer[256];
  268.  
  269.     pos=ftell(src);
  270.     (void)fread((void *)&size,1,1,src);
  271.     if (debug)
  272.         dump(pos,&size,1);
  273.     if (output)
  274.         (void)fwrite((void *)&size,1,1,dest);
  275.     pos=ftell(src);
  276.     (void)fread((void *)buffer,(size_t)size,1,src);
  277.     if (debug)
  278.         dump(pos,buffer,(size_t)size);
  279.     if (output)
  280.         (void)fwrite((void *)buffer,(size_t)size,1,dest);
  281. }
  282.  
  283.  
  284. void transdata(src,dest)
  285. FILE    *src;
  286. FILE    *dest;
  287. {
  288.     unsigned char    size,buffer[256];
  289.  
  290.     do {
  291.         pos=ftell(src);
  292.         (void)fread((void *)&size,1,1,src);
  293.         if (debug)
  294.             dump(pos,&size,1);
  295.         if (output)
  296.             (void)fwrite((void *)&size,1,1,dest);
  297.         pos=ftell(src);
  298.         (void)fread((void *)buffer,(size_t)size,1,src);
  299.         if (debug)
  300.             dump(pos,buffer,(size_t)size);
  301.         if (output)
  302.             (void)fwrite((void *)buffer,(size_t)size,1,dest);
  303.     } while (!feof(src)&&size>0);
  304. }
  305.  
  306.  
  307. int giftrans(src,dest)
  308. FILE    *src;
  309. FILE    *dest;
  310. {
  311.     unsigned char    buffer[3*256],lsd[7],gct[3*256],gce[5];
  312.     unsigned int    cnt,cols,size,gct_size,gct_delay,gce_present;
  313.     struct entry    *rgbptr;
  314.  
  315.  
  316.     /* Header */
  317.     pos=ftell(src);
  318.     (void)fread((void *)buffer,6,1,src);
  319.     if (strncmp((char *)buffer,"GIF",3)) {
  320.         (void)fprintf(stderr,"No GIF file!\n");
  321.         return(1);
  322.     }
  323.     if (verbose) {
  324.         buffer[6]='\0';
  325.         (void)fprintf(stderr,"Header: \"%s\"\n",buffer);
  326.     }
  327.     if (debug)
  328.         dump(pos,buffer,6);
  329.     if (output)
  330.         (void)fputs("GIF89a",dest);
  331.  
  332.     /* Logical Screen Descriptor */
  333.     pos=ftell(src);
  334.     (void)fread((void *)lsd,7,1,src);
  335.     if (verbose) {
  336.         (void)fprintf(stderr,"Logical Screen Descriptor:\n");
  337.         (void)fprintf(stderr,"\tLogical Screen Width: %d pixels\n",readword(lsd));
  338.         (void)fprintf(stderr,"\tLogical Screen Height: %d pixels\n",readword(lsd+2));
  339.         (void)fprintf(stderr,"\tGlobal Color Table Flag: %s\n",readflag(lsd[4]&0x80));
  340.         (void)fprintf(stderr,"\tColor Resolution: %d bits\n",(lsd[4]&0x70>>4)+1);
  341.         if (lsd[4]&0x80) {
  342.             (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8));
  343.             (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7));
  344.             (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]);
  345.         }
  346.         if (lsd[6])
  347.             (void)fprintf(stderr,"\tPixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64);
  348.     }
  349.     if (debug)
  350.         dump(pos,lsd,7);
  351.  
  352.     /* Global Color Table */
  353.     gct_delay=FALSE;
  354.     if (lsd[4]&0x80) {
  355.         gct_size=2<<(lsd[4]&0x7);
  356.         pos=ftell(src);
  357.         (void)fread((void *)gct,gct_size,3,src);
  358.         if (go.index==RGB)
  359.             for(cnt=0;cnt<gct_size&&go.index==RGB;cnt++)
  360.                 if (gct[3*cnt]==go.red&&gct[3*cnt+1]==go.green&&gct[3*cnt+2]==go.blue)
  361.                     go.index=cnt;
  362.         if (go.index>=0) {
  363.             if (gn.index>=0) {
  364.                 gn.red=gct[3*gn.index];
  365.                 gn.green=gct[3*gn.index+1];
  366.                 gn.blue=gct[3*gn.index+2];
  367.             }
  368.             gct[3*go.index]=gn.red;
  369.             gct[3*go.index+1]=gn.green;
  370.             gct[3*go.index+2]=gn.blue;
  371.         }
  372.         if (bc.index==RGB)
  373.             for(cnt=0;cnt<gct_size&&bc.index==RGB;cnt++)
  374.                 if (gct[3*cnt]==bc.red&&gct[3*cnt+1]==bc.green&&gct[3*cnt+2]==bc.blue)
  375.                     bc.index=cnt;
  376.         if (bc.index>=0)
  377.             lsd[5]=bc.index;
  378.         if (tc.index==RGB)
  379.             for(cnt=0;cnt<gct_size&&tc.index==RGB;cnt++)
  380.                 if (gct[3*cnt]==tc.red&&gct[3*cnt+1]==tc.green&&gct[3*cnt+2]==tc.blue)
  381.                     tc.index=cnt;
  382.         if (tc.index==OTHER)
  383.             tc.index=lsd[5];
  384.         if (tn.index>=0) {
  385.             tn.red=gct[3*tn.index];
  386.             tn.green=gct[3*tn.index+1];
  387.             tn.blue=gct[3*tn.index+2];
  388.         }
  389.         if (tn.index!=NONE)
  390.             gct_delay=TRUE;
  391.     }
  392.     if (output)
  393.         (void)fwrite((void *)lsd,7,1,dest);
  394.     if (lsd[4]&0x80) {
  395.         if (list||verbose) {
  396.             (void)fprintf(stderr,"Global Color Table:\n");
  397.             for(cnt=0;cnt<gct_size;cnt++) {
  398.                 (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d",cnt,gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  399.                 (void)fprintf(stderr,", #%02x%02x%02x",gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  400.                 for (rgbptr=root,cols=0;rgbptr;rgbptr=rgbptr->next)
  401.                     if (rgbptr->red==gct[3*cnt]&&rgbptr->green==gct[3*cnt+1]&&rgbptr->blue==gct[3*cnt+2])
  402.                         (void)fprintf(stderr,"%s%s",cols++?", ":" (",rgbptr->name);
  403.                 (void)fprintf(stderr,"%s\n",cols?")":"");
  404.             }
  405.         }
  406.         if (debug)
  407.             dump(pos,gct,gct_size*3);
  408.         if (output&&(!gct_delay))
  409.             (void)fwrite((void *)gct,gct_size,3,dest);
  410.     }
  411.  
  412.     gce_present=FALSE;
  413.     do {
  414.         pos=ftell(src);
  415.         (void)fread((void *)buffer,1,1,src);
  416.         switch (buffer[0]) {
  417.         case 0x2c:    /* Image Descriptor */
  418.             if (verbose)
  419.                 (void)fprintf(stderr,"Image Descriptor:\n");
  420.             (void)fread((void *)(buffer+1),9,1,src);
  421.             /* Write Graphic Control Extension */
  422.             if (tc.index>=0||gce_present) {
  423.                 if (!gce_present) {
  424.                     gce[0]=0;
  425.                     gce[1]=0;
  426.                     gce[2]=0;
  427.                 }
  428.                 if (tc.index>=0) {
  429.                     gce[0]|=0x01;    /* Set Transparent Color Flag */
  430.                     gce[3]=tc.index;    /* Set Transparent Color Index */
  431.                 }
  432.                 else if (gce[0]&0x01)
  433.                     tc.index=gce[3];    /* Remember Transparent Color Index */
  434.                 gce[4]=0;
  435.                 if (tc.index>=0&&(!(buffer[8]&0x80))) { /* Transparent Color Flag set and no Local Color Table */
  436.                     gct[3*tc.index]=tn.red;
  437.                     gct[3*tc.index+1]=tn.green;
  438.                     gct[3*tc.index+2]=tn.blue;
  439.                 }
  440.                 if (output&&gct_delay) {
  441.                     (void)fwrite((void *)gct,gct_size,3,dest);
  442.                     gct_delay=FALSE;
  443.                 }
  444.                 if (output) {
  445.                     (void)fputs("\041\371\004",dest);
  446.                     (void)fwrite((void *)gce,5,1,dest);
  447.                 }
  448.             }
  449.             if (output&&gct_delay) {
  450.                 if (verbose)
  451.                     (void)fprintf(stderr,"Warning: Global Color Table has not been modified as no Transparent Color Index has been set\n");
  452.                 (void)fwrite((void *)gct,gct_size,3,dest);
  453.                 gct_delay=FALSE;
  454.             }
  455.             /* Write Image Descriptor */
  456.             if (verbose) {
  457.                 (void)fprintf(stderr,"\tImage Left Position: %d pixels\n",readword(buffer+1));
  458.                 (void)fprintf(stderr,"\tImage Top Position: %d pixels\n",readword(buffer+3));
  459.                 (void)fprintf(stderr,"\tImage Width: %d pixels\n",readword(buffer+5));
  460.                 (void)fprintf(stderr,"\tImage Height: %d pixels\n",readword(buffer+7));
  461.                 (void)fprintf(stderr,"\tLocal Color Table Flag: %s\n",readflag(buffer[9]&0x80));
  462.                 (void)fprintf(stderr,"\tInterlace Flag: %s\n",readflag(buffer[9]&0x40));
  463.                 if (buffer[9]&0x80) {
  464.                     (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(buffer[9]&0x20));
  465.                     (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(buffer[9]&0x7));
  466.                 }
  467.             }
  468.             if (debug)
  469.                 dump(pos,buffer,10);
  470.             if (output)
  471.                 (void)fwrite((void *)buffer,10,1,dest);
  472.             /* Local Color Table */
  473.             if (buffer[8]&0x80) {
  474.                 size=2<<(buffer[8]&0x7);
  475.                 pos=ftell(src);
  476.                 (void)fread((void *)buffer,size,3,src);
  477.                 if (verbose) {
  478.                     (void)fprintf(stderr,"Local Color Table:\n");
  479.                     for(cnt=0;cnt<size;cnt++)
  480.                         (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d\n",cnt,buffer[3*cnt],buffer[3*cnt+1],buffer[3*cnt+2]);
  481.                 }
  482.                 if (tc.index>=0) { /* Transparent Color Flag set */
  483.                     buffer[3*tc.index]=tn.red;
  484.                     buffer[3*tc.index+1]=tn.green;
  485.                     buffer[3*tc.index+2]=tn.blue;
  486.                 }
  487.                 if (debug)
  488.                     dump(pos,buffer,size*3);
  489.                 if (output)
  490.                     (void)fwrite((void *)buffer,size,3,dest);
  491.             }
  492.             /* Table Based Image Data */
  493.             pos=ftell(src);
  494.             (void)fread((void *)buffer,1,1,src);
  495.             if (verbose) {
  496.                 (void)fprintf(stderr,"Table Based Image Data:\n");
  497.                 (void)fprintf(stderr,"\tLZW Minimum Code Size: 0x%02x\n",buffer[0]);
  498.             }
  499.             if (debug)
  500.                 dump(pos,buffer,1);
  501.             if (output)
  502.                 (void)fwrite((void *)buffer,1,1,dest);
  503.             transdata(src,dest);
  504.             gce_present=FALSE;
  505.             break;
  506.         case 0x3b:    /* Trailer */
  507.             if (verbose)
  508.                 (void)fprintf(stderr,"Trailer\n");
  509.             if (debug)
  510.                 dump(pos,buffer,1);
  511.             if (comment&&*comment&&output) {
  512.                 (void)fputs("\041\376",dest);
  513.                 writedata(dest,(unsigned char *)comment,strlen(comment));
  514.             }
  515.             if (output)
  516.                 (void)fwrite((void *)buffer,1,1,dest);
  517.             break;
  518.         case 0x21:    /* Extension */
  519.             (void)fread((void *)(buffer+1),1,1,src);
  520.             switch (buffer[1]) {
  521.             case 0x01:    /* Plain Text Extension */
  522.                 if (output&&gct_delay) {
  523.                     if (verbose)
  524.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Plain Text Extension\n");
  525.                     (void)fwrite((void *)gct,gct_size,3,dest);
  526.                     gct_delay=FALSE;
  527.                 }
  528.                 if (verbose)
  529.                     (void)fprintf(stderr,"Plain Text Extension\n");
  530.                 if (debug)
  531.                     dump(pos,buffer,2);
  532.                 if (output)
  533.                     (void)fwrite((void *)buffer,2,1,dest);
  534.                 transblock(src,dest);
  535.                 transdata(src,dest);
  536.                 break;
  537.             case 0xf9:    /* Graphic Control Extension */
  538.                 if (verbose)
  539.                     (void)fprintf(stderr,"Graphic Control Extension:\n");
  540.                 (void)fread((void *)(buffer+2),1,1,src);
  541.                 size=buffer[2];
  542.                 (void)fread((void *)gce,size,1,src);
  543.                 if (verbose) {
  544.                     (void)fprintf(stderr,"\tDisposal Method: %d ",gce[0]&0x1c>>2);
  545.                     switch (gce[0]&0x1c>>2) {
  546.                     case 0:
  547.                         (void)fprintf(stderr,"(no disposal specified)\n");
  548.                         break;
  549.                     case 1:
  550.                         (void)fprintf(stderr,"(do not dispose)\n");
  551.                         break;
  552.                     case 2:
  553.                         (void)fprintf(stderr,"(restore to background color)\n");
  554.                         break;
  555.                     case 3:
  556.                         (void)fprintf(stderr,"(restore to previous)\n");
  557.                         break;
  558.                     default:
  559.                         (void)fprintf(stderr,"(to be defined)\n");
  560.                     }
  561.                     (void)fprintf(stderr,"\tUser Input Flag: %s\n",readflag(gce[0]&0x2));
  562.                     (void)fprintf(stderr,"\tTransparent Color Flag: %s\n",readflag(gce[0]&0x1));
  563.                     (void)fprintf(stderr,"\tDelay Time: %d\n",readword(gce+1));
  564.                     if (gce[0]&0x1)
  565.                         (void)fprintf(stderr,"\tTransparent Color Index: %d\n",gce[3]);
  566.                 }
  567.                 if (debug) {
  568.                     dump(pos,buffer,3);
  569.                     dump(pos+3,gce,size);
  570.                 }
  571.                 pos=ftell(src);
  572.                 (void)fread((void *)buffer,1,1,src);
  573.                 if (debug)
  574.                     dump(pos,buffer,1);
  575.                 gce_present=TRUE;
  576.                 break;
  577.             case 0xfe:    /* Comment Extension */
  578.                 if (verbose)
  579.                     (void)fprintf(stderr,"Comment Extension\n");
  580.                 if (debug)
  581.                     dump(pos,buffer,2);
  582.                 if (skipcomment)
  583.                     skipdata(src);
  584.                 else {
  585.                     if (output&&gct_delay) {
  586.                         if (verbose)
  587.                             (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Comment Extension\n");
  588.                         (void)fwrite((void *)gct,gct_size,3,dest);
  589.                         gct_delay=FALSE;
  590.                     }
  591.                     if (output)
  592.                         (void)fwrite((void *)buffer,2,1,dest);
  593.                     transdata(src,dest);
  594.                 }
  595.                 break;
  596.             case 0xff:    /* Application Extension */
  597.                 if (output&&gct_delay) {
  598.                     if (verbose)
  599.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Application Extension\n");
  600.                     (void)fwrite((void *)gct,gct_size,3,dest);
  601.                     gct_delay=FALSE;
  602.                 }
  603.                 if (verbose)
  604.                     (void)fprintf(stderr,"Application Extension\n");
  605.                 if (debug)
  606.                     dump(pos,buffer,2);
  607.                 if (output)
  608.                     (void)fwrite((void *)buffer,2,1,dest);
  609.                 transblock(src,dest);
  610.                 transdata(src,dest);
  611.                 break;
  612.             default:
  613.                 if (output&&gct_delay) {
  614.                     if (verbose)
  615.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to an unknown Extension\n");
  616.                     (void)fwrite((void *)gct,gct_size,3,dest);
  617.                     gct_delay=FALSE;
  618.                 }
  619.                 if (verbose)
  620.                     (void)fprintf(stderr,"Unknown label: 0x%02x\n",buffer[1]);
  621.                 if (debug)
  622.                     dump(pos,buffer,2);
  623.                 if (output)
  624.                     (void)fwrite((void *)buffer,2,1,dest);
  625.                 transblock(src,dest);
  626.                 transdata(src,dest);
  627.                 break;
  628.             }
  629.             break;
  630.         default:
  631.             (void)fprintf(stderr,"0x%08lx: Unknown extension 0x%02x!\n",ftell(src)-1,buffer[0]);
  632.             if (debug)
  633.                 dump(pos,buffer,1);
  634.             return(1);
  635.         }
  636.     } while (buffer[0]!=0x3b&&!feof(src));
  637.     return(buffer[0]==0x3b?SUCCESS:FAILURE);
  638. }
  639.  
  640.  
  641.  
  642. int getindex(c,arg)
  643. struct color    *c;
  644. char    *arg;
  645. {
  646.     struct entry    *ptr;
  647.  
  648.     if ('0'<=*arg&&*arg<='9')
  649.         c->index=atoi(arg);
  650.     else if (*arg=='#') {
  651.         if (strlen(arg)==4) {
  652.             c->index=RGB;
  653.             c->red=hex(arg[1])<<4;
  654.             c->green=hex(arg[2])<<4;
  655.             c->blue=hex(arg[3])<<4;
  656.         }
  657.         else if (strlen(arg)==7) {
  658.             c->index=RGB;
  659.             c->red=(hex(arg[1])<<4)+hex(arg[2]);
  660.             c->green=(hex(arg[3])<<4)+hex(arg[4]);
  661.             c->blue=(hex(arg[5])<<4)+hex(arg[6]);
  662.         }
  663.         else {
  664.             (void)fprintf(stderr,"%s: illegal color specification: %s\n",image,arg);
  665.             return(FAILURE);
  666.         }
  667.     }
  668.     else {
  669.         for (ptr=root;ptr&&c->index!=RGB;ptr=ptr->next)
  670.             if (!strcmp(ptr->name,arg)) {
  671.                 c->index=RGB;
  672.                 c->red=ptr->red;
  673.                 c->green=ptr->green;
  674.                 c->blue=ptr->blue;
  675.             }
  676.         if (c->index!=RGB) {
  677.             (void)fprintf(stderr,"%s: no such color: %s\n",image,arg);
  678.             return(FAILURE);
  679.         }
  680.     }
  681.     return(SUCCESS);
  682. }
  683.  
  684.  
  685.  
  686. void usage()
  687. {
  688.     (void)fprintf(stderr,"Usage: %s [-t color|-T] [-B color] [-b color] [-g oldcolor=newcolor] [-c comment|-C] [-l|-L|-V] [-o filename] [-e filename] [filename]\n",image);
  689.     (void)fprintf(stderr,"Convert any GIF file into a GIF89a, with the folloing changes possible:\n");
  690.     (void)fprintf(stderr,"-t Specify the transparent color\n");
  691.     (void)fprintf(stderr,"-T Index of the transparent color is the background color index\n");
  692.     (void)fprintf(stderr,"-B Specify the transparent color's new value\n");
  693.     (void)fprintf(stderr,"-b Specify the background color\n");
  694.     (void)fprintf(stderr,"-g Change a color in the global color table\n");
  695.     (void)fprintf(stderr,"-c Add a comment\n");
  696.     (void)fprintf(stderr,"-C Remove old comment\n");
  697.     (void)fprintf(stderr,"-l Only list the color table\n");
  698.     (void)fprintf(stderr,"-L Verbose output of GIFs contents\n");
  699.     (void)fprintf(stderr,"-V Verbose output while converting\n");
  700.     (void)fprintf(stderr,"-o Redirect stdout to a file\n");
  701.     (void)fprintf(stderr,"-e Redirect stderr to a file\n");
  702.     if (*rgb)
  703.         (void)fprintf(stderr,"Colors may be specified as index, as rgb.txt entry or in the #rrggbb form.\n");
  704.     else
  705.         (void)fprintf(stderr,"Colors may be specified as index or in the #rrggbb form.\n");
  706.     exit(1);
  707. }
  708.  
  709.  
  710. int main(argc,argv)
  711. int    argc;
  712. char    *argv[];
  713. {
  714.     int        c;
  715.     extern char    *optarg;
  716.     extern int    optind;
  717.     char        error[2*MAXPATHLEN+14],line[BUFSIZ],*ptr,*nptr,*oname,*ename;
  718.     struct entry    **next;
  719.     FILE        *src;
  720.     int        stat;
  721.  
  722.     image=argv[0];
  723.     root=NULL;
  724.     if (*rgb)
  725.         if ((src=fopen(rgb,"r"))!=NULL) {
  726.             next= &root;
  727.             while (fgets(line,sizeof(line),src)) {
  728.                 *next=(struct entry *)malloc(sizeof(struct entry));
  729.                 for (ptr=line;strchr(" \t",*ptr);ptr++);
  730.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  731.                 *ptr++='\0';
  732.                 (*next)->red=atoi(nptr);
  733.                 for (;strchr(" \t",*ptr);ptr++);
  734.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  735.                 *ptr++='\0';
  736.                 (*next)->green=atoi(nptr);
  737.                 for (;strchr(" \t",*ptr);ptr++);
  738.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  739.                 *ptr++='\0';
  740.                 (*next)->blue=atoi(nptr);
  741.                 for (;strchr(" \t",*ptr);ptr++);
  742.                 for (nptr=ptr;!strchr(" \t\r\n",*ptr);ptr++);
  743.                 *ptr='\0';
  744.                 (void)strcpy((*next)->name=(char *)malloc(strlen(nptr)+1),nptr);
  745.                 (*next)->next=NULL;
  746.                 next= &(*next)->next;
  747.             }
  748.             (void)fclose(src);
  749.         }
  750.         else {
  751. #ifndef MSDOS
  752.             (void)sprintf(error,"%s: cannot open %s",image,rgb);
  753.             perror(error);
  754.             return(FAILURE);
  755. #else /* MSDOS */
  756.             *rgb='\0';
  757. #endif
  758.         }
  759.  
  760.     bc.index=NONE;
  761.     tc.index=NONE;
  762.     tn.index=NONE;
  763.     go.index=NONE;
  764.     gn.index=NONE;
  765.     comment=NULL;
  766.     skipcomment=FALSE;
  767.     verbose=FALSE;
  768.     output=TRUE;
  769.     debug=FALSE;
  770.     oname=NULL;
  771.     ename=NULL;
  772.     while ((c=getopt(argc,argv,"t:TB:b:g:c:ClLVDo:e:vh?")) != EOF)
  773.         switch ((char)c) {
  774.         case 'b':
  775.             if (getindex(&bc,optarg))
  776.                 return(FAILURE);
  777.             break;
  778.         case 't':
  779.             if (getindex(&tc,optarg))
  780.                 return(FAILURE);
  781.             break;
  782.         case 'T':
  783.             tc.index=OTHER;
  784.             break;
  785.         case 'B':
  786.             if (getindex(&tn,optarg))
  787.                 return(FAILURE);
  788.             break;
  789.         case 'g':
  790.             if ((ptr=strchr(optarg,'='))!=NULL) {
  791.                 *ptr++='\0';
  792.                 if (getindex(&go,optarg))
  793.                     return(FAILURE);
  794.                 if (getindex(&gn,ptr))
  795.                     return(FAILURE);
  796.             }
  797.             else
  798.                 usage();
  799.             break;
  800.         case 'c':
  801.             comment=optarg;
  802.             break;
  803.         case 'C':
  804.             skipcomment=TRUE;
  805.             break;
  806.         case 'l':
  807.             list=TRUE;
  808.             output=FALSE;
  809.             break;
  810.         case 'L':
  811.             verbose=TRUE;
  812.             output=FALSE;
  813.             break;
  814.         case 'V':
  815.             verbose=TRUE;
  816.             break;
  817.         case 'D':
  818.             debug=TRUE;
  819.             break;
  820.         case 'o':
  821.             oname=optarg;
  822.             break;
  823.         case 'e':
  824.             ename=optarg;
  825.             break;
  826.         case 'v':
  827.             (void)fprintf(stderr,header);
  828.             return(0);
  829.         case 'h':
  830.             (void)fprintf(stderr,header);
  831.         case '?':
  832.             usage();
  833.         }
  834.     if (optind+1<argc||(bc.index==NONE&&tc.index==NONE&&tn.index==NONE&&gn.index==NONE&&comment==NULL&&!skipcomment&&!list&&!verbose))
  835.         usage();
  836.  
  837.     if (oname&&freopen(oname,"wb",stdout)==NULL) {
  838.         (void)sprintf(error,"%s: cannot open %s",image,oname);
  839.         perror(error);
  840.         return(FAILURE);
  841.     }
  842.  
  843.     if (ename&&freopen(ename,"wb",stderr)==NULL) {
  844.         (void)sprintf(error,"%s: cannot open %s",image,ename);
  845.         perror(error);
  846.         return(FAILURE);
  847.     }
  848.  
  849. #ifdef MSDOS
  850.     if(oname==NULL&&(stdout->flags&_F_TERM)==0&&setmode(fileno(stdout),O_BINARY)!=0) {
  851.         (void)fprintf(stderr,"%s: can't set stdout's mode to binary\n",image);
  852.         exit(2);
  853.     }
  854.     if(optind==argc&&(stdin->flags&_F_TERM)==0&&setmode(fileno(stdin),O_BINARY)) {
  855.         (void)fprintf(stderr,"%s: can't set stdin's mode to binary\n",image);
  856.         exit(2);
  857.     }
  858. #endif /* MSDOS */
  859.  
  860.     if (optind<argc)
  861.         if (strcmp(argv[optind],"-"))
  862.             if ((src=fopen(argv[optind],"rb"))!=NULL) {
  863.                 stat=giftrans(src,stdout);
  864.                 (void)fclose(src);
  865.             }
  866.             else {
  867.                 (void)sprintf(error,"%s: cannot open %s",image,argv[optind]);
  868.                 perror(error);
  869.                 return(FAILURE);
  870.             }
  871.         else
  872.             stat=giftrans(stdin,stdout);
  873.     else
  874.         stat=giftrans(stdin,stdout);
  875.  
  876.     (void)fclose(stdout);
  877.     (void)fclose(stderr);
  878.     return(stat);
  879. }
  880.